
#include "ctc_const.h"
#include "ctc_error.h"
#include "sys_usw_common.h"
#include "sys_usw_nexthop_api.h"
#include "sys_usw_nexthop_hw.h"
#include "sys_usw_nexthop.h"
#include "sys_usw_dma.h"
#include "drv_api.h"

int32
sys_tmm_nh_get_edit_param(uint8 lchip, void* p_nh_db, void* p_para)
{
    sys_nh_info_misc_t* p_nh_info;
    ctc_misc_nh_param_t* p_misc_param = NULL;
    uint32 cmd = 0;
    ctc_misc_nh_flex_edit_param_t* p_flex_param = NULL;
    hw_mac_addr_t hw_mac;

    p_nh_info = (sys_nh_info_misc_t*)(p_nh_db);
    p_misc_param = (ctc_misc_nh_param_t*)p_para;
    p_flex_param = &p_misc_param->misc_param.flex_edit;

   if (p_nh_info->packet_type == CTC_MISC_NH_PACKET_TYPE_MPLS)
    {
        uint8 index = 0;
        DsL3EditAddMpls1X_m mpls_edit;
        p_flex_param->label_num = p_nh_info->label_num;
        for (index = 0; index < p_nh_info->label_num; index++)
        {
            if (DRV_FROM_AT(lchip) && (0 == index))
            {
                cmd = DRV_IOR(DsL3EditAddMpls1X0_t, DRV_ENTRY_FLAG);
            }
            else
            {
                cmd = DRV_IOR(DsL3EditAddMpls1X_t, DRV_ENTRY_FLAG);
            }
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, index?p_nh_info->next_l3edit_offset:p_nh_info->dsl3edit_offset, cmd, &mpls_edit));
            _sys_usw_nh_decode_dsmpls(lchip, &mpls_edit, &p_flex_param->label[index]);
        }
    }
    else if (p_nh_info->l2edit_entry_type == SYS_NH_ENTRY_TYPE_L2EDIT_INNER_SWAP)
    {
        DsL2EditRwEth1X_m l2_inner_swap;
        cmd = DRV_IOR(DsL2EditRwEth1X_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_nh_info->dsl2edit_offset, cmd, &l2_inner_swap);
        GetDsL2EditRwEth1X(A, macDa_f, &l2_inner_swap, hw_mac);
        SYS_USW_SET_USER_MAC(p_flex_param->mac_da, hw_mac);
        p_flex_param->ether_type = GetDsL2EditRwEth1X(V, etherType_f, &l2_inner_swap);
    }
    else if (p_nh_info->l2edit_entry_type == SYS_NH_ENTRY_TYPE_L2EDIT_SWAP)
    {
        DsL2EditRwEth2X_m l2_swap;
        cmd = DRV_IOR(DsL2EditRwEth2X_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_nh_info->dsl2edit_offset, cmd, &l2_swap);
        GetDsL2EditRwEth2X(A, macDa_f, &l2_swap, hw_mac);
        SYS_USW_SET_USER_MAC(p_flex_param->mac_da, hw_mac);
        GetDsL2EditRwEth2X(A, macSa_f, &l2_swap, hw_mac);
        SYS_USW_SET_USER_MAC(p_flex_param->mac_sa, hw_mac);
        p_flex_param->ether_type = GetDsL2EditRwEth2X(V, etherType_f, &l2_swap);
    }
    else if (p_nh_info->l2edit_entry_type == SYS_NH_ENTRY_TYPE_L2EDIT_OF_6W)
    {
        DsL2EditRwEth2X_m l2_edit;
        DsL2EditRwEthVlanActionProfile_m vlan_action;
        cmd = DRV_IOR(DsL2EditRwEth2X_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_nh_info->dsl2edit_offset, cmd, &l2_edit);
        GetDsL2EditRwEth2X(A, macDa_f, &l2_edit, hw_mac);
        SYS_USW_SET_USER_MAC(p_flex_param->mac_da, hw_mac);
        GetDsL2EditRwEth2X(A, macSa_f, &l2_edit, hw_mac);
        SYS_USW_SET_USER_MAC(p_flex_param->mac_sa, hw_mac);
        p_flex_param->ether_type = GetDsL2EditRwEth2X(V, etherType_f, &l2_edit);
        p_flex_param->new_svid = GetDsL2EditRwEth2X(V, sVlanId_f, &l2_edit);
        p_flex_param->new_scos = GetDsL2EditRwEth2X(V, sCos_f, &l2_edit);
        p_flex_param->new_cvid = GetDsL2EditRwEth2X(V, cVlanId_f, &l2_edit);
        p_flex_param->new_ccos = GetDsL2EditRwEth2X(V, cCos_f, &l2_edit);

        cmd = DRV_IOR(DsL2EditRwEthVlanActionProfile_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_nh_info->vlan_profile_id, cmd, &vlan_action);
        if (GetDsL2EditRwEthVlanActionProfile(V, sVlanTpidIndexEn_f, &vlan_action))
        {
            p_flex_param->new_stpid_en = 1;
            p_flex_param->new_stpid_idx = GetDsL2EditRwEthVlanActionProfile(V, sVlanTpidIndex_f, &vlan_action);
        }
    }

    if (p_nh_info->l3edit_entry_type == (SYS_NH_ENTRY_TYPE_L3EDIT_OF_6W + SYS_NH_TYPE_STEP_TO_INNER))
    {
        uint8 dscp_mode = 0;
        DsL3EditRwIp4_m  edit_profile;

        cmd = DRV_IOR(DRV_FROM_AT(lchip)? DsL3EditRwIp40_t : DsL3EditRwIp4_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_nh_info->dsl3edit_offset, cmd, &edit_profile);
        p_flex_param->ip_da.ipv4 = GetDsL3EditRwIp4(V, ipAddr0_f, &edit_profile);
        p_flex_param->ip_sa.ipv4 = GetDsL3EditRwIp4(V, ipAddr1_f, &edit_profile);
        p_flex_param->protocol = GetDsL3EditRwIp4(V, protocol_f, &edit_profile);
        p_flex_param->ttl = GetDsL3EditRwIp4(V, ttl_f, &edit_profile);

        if (GetDsL3EditRwIp4(V, ecnRemarkMode_f, &edit_profile))
        {
            p_flex_param->ecn_select = (GetDsL3EditRwIp4(V, ecnRemarkMode_f, &edit_profile)==1)?CTC_NH_ECN_SELECT_ASSIGN:CTC_NH_ECN_SELECT_MAP;
            p_flex_param->ecn = (GetDsL3EditRwIp4(V, tos_f, &edit_profile)&0x3);
        }
        dscp_mode = GetDsL3EditRwIp4(V, dscpRemarkMode_f, &edit_profile);
        p_flex_param->dscp_select = (dscp_mode==1)?CTC_NH_DSCP_SELECT_ASSIGN:
            ((dscp_mode==2)?CTC_NH_DSCP_SELECT_MAP:((dscp_mode==3)?CTC_NH_DSCP_SELECT_PACKET:CTC_NH_DSCP_SELECT_NONE));
        p_flex_param->dscp_or_tos = ((GetDsL3EditRwIp4(V, tos_f, &edit_profile)>> 2) & 0x3f);
        if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_ICMP)
        {
            p_flex_param->icmp_code = GetDsL3EditRwIp4(V, l4Port0_f, &edit_profile);
            p_flex_param->icmp_type = GetDsL3EditRwIp4(V, l4Port1_f, &edit_profile);
        }
        else if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_GRE)
        {
            p_flex_param->gre_key = ((GetDsL3EditRwIp4(V, l4Port1_f, &edit_profile)<<16) | GetDsL3EditRwIp4(V, l4Port0_f, &edit_profile));
        }
        else if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_UDPORTCP)
        {
            p_flex_param->l4_dst_port = GetDsL3EditRwIp4(V, l4Port0_f, &edit_profile);
            p_flex_param->l4_src_port = GetDsL3EditRwIp4(V, l4Port1_f, &edit_profile);
        }
    }
    else if (p_nh_info->l3edit_entry_type == (SYS_NH_ENTRY_TYPE_L3EDIT_OF_12W + SYS_NH_TYPE_STEP_TO_INNER))
    {
        uint8 dscp_mode = 0;
        DsL3EditRwIp6_m edit_profile;
        ipv6_addr_t hw_ipv6_address;

        cmd = DRV_IOR(DRV_FROM_AT(lchip)? DsL3EditRwIp60_t : DsL3EditRwIp6_t, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, p_nh_info->dsl3edit_offset, cmd, &edit_profile);
        if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_ICMP)
        {
            p_flex_param->icmp_code = GetDsL3EditRwIp6(V, l4Port0_f, &edit_profile);
            p_flex_param->icmp_type = GetDsL3EditRwIp6(V, l4Port1_f, &edit_profile);
        }
        else if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_GRE)
        {
            p_flex_param->gre_key = (GetDsL3EditRwIp6(V, l4Port1_f, &edit_profile)<<16) | GetDsL3EditRwIp6(V, l4Port0_f, &edit_profile);
        }
        else if (p_flex_param->packet_type == CTC_MISC_NH_PACKET_TYPE_UDPORTCP)
        {
            p_flex_param->l4_dst_port = GetDsL3EditRwIp6(V, l4Port0_f, &edit_profile);
            p_flex_param->l4_src_port = GetDsL3EditRwIp6(V, l4Port1_f, &edit_profile);
        }

        p_flex_param->flow_label = GetDsL3EditRwIp6(V, flowLabel_f, &edit_profile);
        p_flex_param->protocol = GetDsL3EditRwIp6(V, protocol_f, &edit_profile);
        p_flex_param->ttl = GetDsL3EditRwIp6(V, ttl_f, &edit_profile);
        if (CTC_FLAG_ISSET(p_flex_param->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_IPDA))
        {
            GetDsL3EditRwIp6(A, ipAddr0_f,         &edit_profile,  hw_ipv6_address);
            p_flex_param->ip_da.ipv6[0] = (hw_ipv6_address[3]);
            p_flex_param->ip_da.ipv6[1] = (hw_ipv6_address[2]);
            p_flex_param->ip_da.ipv6[2] = (hw_ipv6_address[1]);
            p_flex_param->ip_da.ipv6[3] = (hw_ipv6_address[0]);
        }

        if (CTC_FLAG_ISSET(p_flex_param->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_IPSA))
        {
            GetDsL3EditRwIp6(A, ipAddr1_f,         &edit_profile,  hw_ipv6_address);
            p_flex_param->ip_sa.ipv6[0] = (hw_ipv6_address[3]);
            p_flex_param->ip_sa.ipv6[1] = (hw_ipv6_address[2]);
            p_flex_param->ip_sa.ipv6[2] = (hw_ipv6_address[1]);
            p_flex_param->ip_sa.ipv6[3] = (hw_ipv6_address[0]);
        }
        dscp_mode = GetDsL3EditRwIp6(V, dscpRemarkMode_f , &edit_profile);
        p_flex_param->ecn_select = (GetDsL3EditRwIp6(V, ecnRemarkMode_f, &edit_profile) == 1)?CTC_NH_ECN_SELECT_ASSIGN:CTC_NH_ECN_SELECT_MAP;
        p_flex_param->dscp_select = (dscp_mode == 1)?CTC_NH_DSCP_SELECT_ASSIGN:
            ((dscp_mode == 2)?CTC_NH_DSCP_SELECT_MAP:((dscp_mode == 3)?CTC_NH_DSCP_SELECT_PACKET:CTC_NH_DSCP_SELECT_NONE));
        p_flex_param->dscp_or_tos = (GetDsL3EditRwIp6(V, tos_f , &edit_profile)>>2) & 0x3f;
        p_flex_param->ecn = (GetDsL3EditRwIp6(V, tos_f , &edit_profile) & 0x3);
    }

    if (CTC_FLAG_ISSET(p_flex_param->flag, CTC_MISC_NH_FLEX_EDIT_REPLACE_VLAN_TAG) && sys_usw_nh_is_xgpon_hybrid(lchip, p_misc_param->logic_port))
    {
        uint32 cmd = 0;
        DsNextHop8W_m ds_nh;
        ctc_vlan_egress_edit_info_t vlan_info;
        sal_memset(&vlan_info, 0, sizeof(vlan_info));
        cmd = DRV_IOR(DsNextHop8W_t, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, p_nh_info->hdr.dsnh_offset, cmd, &ds_nh));
        vlan_info.svlan_edit_type = p_nh_info->svlan_edit_type;
        vlan_info.cvlan_edit_type = p_nh_info->cvlan_edit_type;
        _sys_usw_nh_decode_vlan_edit(lchip, &vlan_info, &ds_nh);
        p_flex_param->new_svid = vlan_info.output_svid;
        p_flex_param->new_cvid = vlan_info.output_cvid;
        if (CTC_FLAG_ISSET(vlan_info.edit_flag, CTC_VLAN_EGRESS_EDIT_OUTPUT_SVLAN_TPID_VALID))
        {
            p_flex_param->new_stpid_en = 1;
            p_flex_param->new_stpid_idx = vlan_info.svlan_tpid_index;
        }
    }

    return CTC_E_NONE;
}

int32
sys_tmm_nh_ecmp_clear_dlb_flow(uint8 lchip, void* p_nhdb_param)
{
    sys_dma_tbl_rw_t dma_rw;
    drv_work_platform_type_t platform_type;    
    sys_nh_info_ecmp_t* p_nhdb = (sys_nh_info_ecmp_t* )p_nhdb_param;
    DsEcmpDlbFlowStateLeft_m* p_dlb_flow_left;
    uint32 tbl_id[2] = {DsEcmpDlbFlowStateLeft_t, DsEcmpDlbFlowStateRight_t};
    uint32 cmd = 0;
    uint16 loop1 = 0;
    uint16 loop2 = 0;

    drv_get_platform_type(lchip, &platform_type);
    if (platform_type != HW_PLATFORM)
    {
        return CTC_E_NONE;
    }
    /*left & right*/
    for(loop1 = 0; loop1 < 2; loop1++)
    {            
        sal_memset(&dma_rw, 0, sizeof(sys_dma_tbl_rw_t));
        dma_rw.entry_len = TABLE_ENTRY_SIZE(lchip, tbl_id[loop1]);
        dma_rw.entry_num = TABLE_MAX_INDEX(lchip, tbl_id[loop1]);
        dma_rw.entry_offset = TABLE_ENTRY_OFFSET(lchip, tbl_id[loop1]);
        MALLOC_ZERO(MEM_NEXTHOP_MODULE, dma_rw.buffer, dma_rw.entry_len*dma_rw.entry_num);
        if (NULL == dma_rw.buffer)
        {
            return CTC_E_NO_MEMORY;
        }
        drv_usw_table_get_hw_addr(lchip, tbl_id[loop1], 0, &dma_rw.tbl_addr, FALSE);
        MCHIP_DMA(lchip)->dma_read_table(lchip, &dma_rw);
        cmd = DRV_IOW(tbl_id[loop1], DRV_ENTRY_FLAG);
        for (loop2 = 0; loop2 < dma_rw.entry_num; loop2++)
        {
            p_dlb_flow_left = (DsEcmpDlbFlowStateLeft_m *)dma_rw.buffer + loop2; 
            if(((GetDsEcmpDlbFlowStateLeft(V, hashKey_f, p_dlb_flow_left) >> 16) & 0xFFF) == p_nhdb->ecmp_group_id)
            {
                SetDsEcmpDlbFlowStateLeft(V, valid_f, p_dlb_flow_left, 0);
                DRV_IOCTL(lchip, loop2, DRV_CMD_PP_EN(cmd), p_dlb_flow_left);
            }
        }
        mem_free(dma_rw.buffer);
    }
    return CTC_E_NONE;
}


